package org.conditure.container;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Set;

/**
 * Defines a component.
 * 
 * @author Elvir
 */
public class ComponentDefinition {
	private Class<?> componentClass;
	private String componentName;
	private ComponentType componentType;
	
	private Set<Field> injectedFields;
	private Set<Method> initializerMethods;
	private Set<Method> destructorMethods;
	
	private Object cachedObject;

	/**
	 * @param componentClass
	 * @param componentName
	 * @param injectedFields
	 * @param initializerMethods
	 * @param destructorMethods
	 * @param object
	 */
	public ComponentDefinition(Class<?> componentClass, String componentName, ComponentType componentType, 
			Set<Field> injectedFields, Set<Method> initializerMethods, Set<Method> destructorMethods) {
		this.componentClass = componentClass;
		this.componentName = componentName;
		this.componentType = componentType;
		
		this.injectedFields = injectedFields;
		this.initializerMethods = initializerMethods;
		this.destructorMethods = destructorMethods;
	}

	/**
	 * @return the componentClass
	 */
	public Class<?> getComponentClass() {
		return componentClass;
	}

	/**
	 * @param componentClass
	 *            the componentClass to set
	 */
	public void setComponentClass(Class<?> componentClass) {
		this.componentClass = componentClass;
	}

	/**
	 * @return the componentName
	 */
	public String getComponentName() {
		return componentName;
	}

	/**
	 * @param componentName
	 *            the componentName to set
	 */
	public void setComponentName(String componentName) {
		this.componentName = componentName;
	}

	/**
	 * @return the injectedFields
	 */
	public Set<Field> getInjectedFields() {
		return injectedFields;
	}

	/**
	 * @param injectedFields
	 *            the injectedFields to set
	 */
	public void setInjectedFields(Set<Field> injectedFields) {
		this.injectedFields = injectedFields;
	}
	
	/**
	 * @return the object
	 * 
	 * @throws IllegalAccessException 
	 * @throws InstantiationException 
	 */
	public Object getObject() throws InstantiationException, IllegalAccessException {
		Object response = null;
		
		switch (componentType) {
			case PROTOTYPE:
				response = componentClass.newInstance();
				break;
			case SINGLETON:
				if (cachedObject == null) {
					cachedObject = componentClass.newInstance();
				}
				
				response = cachedObject;
				break;
		}
		
		return response;
	}

	/**
	 * @return the initializerMethods
	 */
	public Set<Method> getInitializerMethods() {
		return initializerMethods;
	}

	/**
	 * @param initializerMethods the initializerMethods to set
	 */
	public void setInitializerMethods(Set<Method> initializerMethods) {
		this.initializerMethods = initializerMethods;
	}

	/**
	 * @return the destructorMethods
	 */
	public Set<Method> getDestructorMethods() {
		return destructorMethods;
	}

	/**
	 * @param destructorMethods the destructorMethods to set
	 */
	public void setDestructorMethods(Set<Method> destructorMethods) {
		this.destructorMethods = destructorMethods;
	}

	/**
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime
				* result
				+ ((componentClass == null) ? 0 : componentClass.getName()
						.hashCode());
		result = prime * result
				+ ((componentName == null) ? 0 : componentName.hashCode());
		return result;
	}

	/**
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		ComponentDefinition other = (ComponentDefinition) obj;
		if (componentClass == null) {
			if (other.componentClass != null)
				return false;
		} else if (!componentClass.getName().equals(
				other.componentClass.getName()))
			return false;
		if (componentName == null) {
			if (other.componentName != null)
				return false;
		} else if (!componentName.equals(other.componentName))
			return false;
		return true;
	}

	/**
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return "ComponentDefinition [componentClass=" + componentClass
				+ ", componentName=" + componentName + ", injectedFields="
				+ injectedFields + "]";
	}
}
